package com.example.adminsystem.controller;

import com.example.adminsystem.common.ResponseResult;
import com.example.adminsystem.common.PageResponseData;
import com.example.adminsystem.repository.BaseCrudRepository;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.data.domain.Page;
import javax.persistence.criteria.Predicate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.lang.reflect.Field;

public abstract class BaseCrudController<T, ID, CreateDTO, UpdateDTO, BaseQuery> {

    // 获取具体的Repository实例
    protected abstract BaseCrudRepository<T, ID> getRepository();

    // 新增空字符串判断方法
    private boolean isEmptyString(Object value) {
        return value instanceof String && StringUtils.isEmpty((String) value);
    }

    // 构建查询条件的方法
    protected Specification<T> buildSpecification(BaseQuery params) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            try {
                for (Field field : params.getClass().getDeclaredFields()) {
                    field.setAccessible(true);
                    Object value = field.get(params);

                    if (value != null && !isEmptyString(value)) {
                        if (value instanceof String) {
                            String strValue = ((String) value).trim();
                            if (!strValue.isEmpty()) {
                                predicates.add(cb.like(
                                        root.get(field.getName()),
                                        "%" + strValue + "%"
                                ));
                            }
                        } else {
                            predicates.add(cb.equal(
                                    root.get(field.getName()),
                                    value
                            ));
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("构建查询条件失败", e);
            }
            return predicates.isEmpty() ? null : cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    // 新增的方法，用于将DTO转换为实体
    protected T convertToEntityForCreate(CreateDTO dto) {
        try {
            // 通过反射获取实体类类型
            Class<?> entityClass = ((Class<?>) ((java.lang.reflect.ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0]);
            T entity = (T) entityClass.newInstance();
            for (Field field : dto.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                Object value = field.get(dto);
                if (value != null) {
                    String setterName = "set" + field.getName().substring(0, 1).toUpperCase() +
                            field.getName().substring(1);
                    entity.getClass().getMethod(setterName, value.getClass()).invoke(entity, value);
                }
            }
            return entity;
        } catch (Exception e) {
            throw new RuntimeException("DTO转换实体失败", e);
        }
    }

    // 编辑的方法，用于将DTO转换为实体
    protected T convertToEntityForUpdate(UpdateDTO dto) {
        try {
            Class<?> entityClass = ((Class<?>) ((java.lang.reflect.ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0]);
            T entity = (T) entityClass.newInstance();
            for (Field field : dto.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                Object value = field.get(dto);
                if (value != null) {
                    String setterName = "set" + field.getName().substring(0, 1).toUpperCase() + 
                        field.getName().substring(1);
                    entity.getClass().getMethod(setterName, value.getClass()).invoke(entity, value);
                }
            }
            return entity;
        } catch (Exception e) {
            throw new RuntimeException("DTO转换实体失败", e);
        }
    }

    @Operation(summary = "获取所有数据")
    @GetMapping
    public ResponseResult<List<T>> findAll(@ModelAttribute BaseQuery params) {
        return ResponseResult.success(getRepository().findAll(buildSpecification(params)));
    }

    // 新增空字符串判断方法

    @Operation(summary = "分页获取数据")
    @GetMapping("/page")
    public ResponseResult<PageResponseData<T>> findPage(
            @RequestParam int page,
            @RequestParam int page_size,
            @ModelAttribute BaseQuery params
    ) {
        Specification<T> spec = buildSpecification(params);
        Page<T> pageInfo = getRepository().findAll(spec, PageRequest.of(page - 1, page_size));
        PageResponseData<T> responseData = new PageResponseData<>();
        responseData.setResults(pageInfo.getContent());
        responseData.setTotal(pageInfo.getTotalElements());
        responseData.setPage(page);
        responseData.setPageSize(page_size);
        return ResponseResult.success(responseData);
    }

    @Operation(summary = "根据ID获取数据")
    @GetMapping("/{id}")
    public ResponseResult<T> findById(@PathVariable ID id) {
        Optional<T> result = getRepository().findById(id);
        return result.map(ResponseResult::success)
                .orElse(ResponseResult.notFound());
    }

    @Operation(summary = "新增数据")
    @PostMapping
    public ResponseResult<T> create(@RequestBody CreateDTO dto) {
        T entity = convertToEntityForCreate(dto);
        return ResponseResult.success(getRepository().save(entity));
    }

    // 复制实体方法
    private T copyEntity(T source) {
        try {
            Class<?> entityClass = ((Class<?>) ((java.lang.reflect.ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0]);
            T target = (T) entityClass.newInstance();
            
            for (Field field : source.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                Object value = field.get(source);
                if (value != null) {
                    String setterName = "set" + field.getName().substring(0, 1).toUpperCase() + 
                        field.getName().substring(1);
                    target.getClass().getMethod(setterName, field.getType()).invoke(target, value);
                }
            }
            return target;
        } catch (Exception e) {
            throw new RuntimeException("复制实体失败", e);
        }
    }

    @Operation(summary = "更新数据")
    @PutMapping("/{id}") 
    public ResponseResult<T> update(@PathVariable ID id, @RequestBody UpdateDTO dto) throws Exception {
        Optional<T> optionalEntity = getRepository().findById(id);
        if (!optionalEntity.isPresent()) {
            return ResponseResult.notFound();
        }

        T originalEntity = optionalEntity.get();
        T updatedEntity = convertToEntityForUpdate(dto);
        
        // 只将updatedEntity中有值的字段复制到originalEntity
        for (Field field : updatedEntity.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            Object newValue = field.get(updatedEntity);
            if (newValue != null) {
                String fieldName = field.getName();
                String setterName = "set" + fieldName.substring(0, 1).toUpperCase() + 
                    fieldName.substring(1);
                originalEntity.getClass().getMethod(setterName, field.getType())
                    .invoke(originalEntity, newValue);
            }
        }
        
        return ResponseResult.success(getRepository().save(originalEntity));
    }

    @Operation(summary = "删除数据")
    @DeleteMapping("/{id}")
    public ResponseResult<Void> delete(@PathVariable ID id) {
        if (!getRepository().existsById(id)) {
            return ResponseResult.notFound();
        }
        getRepository().deleteById(id);
        return ResponseResult.success();
    }
}
